#include "stdafx.h"
#include ".\population.h"
#include "../TermEngine/Terms/ApplicationTerm.h"
const mapIndDoub& mapIndDoub::operator += (const mapIndDoub& MID){
	mapIndDoub::const_iterator MID_b = MID.begin( );
	for(; MID_b != MID.end( ); MID_b++)
		this->insert(mapIndDoub::value_type(*MID_b));
	return *this;
	}
void mapIndDoub::eraseAll( ){
	 	erase(begin( ), end( ));
		if(!empty( )) throw string("Tantrum");
	}

string PopulationParameters::toString( ) const{
	//"MaxPopulationSize,MaxEvaluationTime,SelectionSize,EliteSize,MaxIndividualSize\n"
	stringstream buff;
	buff<<(unsigned int) MaxPopulationSize;
	buff<<",";
	buff<<(unsigned int) MaxEvaluationTime;
	buff<<",";
	buff<<(unsigned int) SelectionSize;
	buff<<",";
	buff<<(unsigned int) EliteSize;
	buff<<",";
	buff<<(unsigned int) MaxIndividualSize;
	return buff.str();
	}
void PopulationParameters::fromString(const char* str){
	 sscanf(str, "%d,%d,%d,%d,%d",
		 	&MaxPopulationSize, 
			&MaxEvaluationTime,
			&SelectionSize,
			&EliteSize,
			&MaxIndividualSize);
	}
Population::Population(
					   INDIVIDUAL* (*Creator)( void ),
					   Individual (*Procreator) (const Individual, const Individual),
					   void (*Mutator) (Individual),
					   PopulationParameters* Pa, 
					   Ticker TicToc):
Params(Pa), generationCount(0), Generator(Creator), Spawn(Procreator), Mutate(Mutator){
	fillByGenerating(TicToc);
	}

void Population::insert(Individual Ind, double FitVal){
	//insert an individual in the population
	m_Individuals[Ind] = FitVal;
	Individual Inserted = NULL;
	size_t specieCtr = 0;
	while ((specieCtr < Taxonomie.size( )) && ( !Inserted )){
		Inserted = 	(Taxonomie[ specieCtr ])->insert( Ind );
		specieCtr++;
		}
	if(!Inserted) Taxonomie.push_back( new Species( Ind ) );	
	}	
void Population::insertMap (map<Individual, double>& PopSet){
	map<Individual, double>::iterator Beg = PopSet.begin( );
	while(Beg != PopSet.end( )){
		insert(Beg->first, Beg->second);
		Beg++;
		}
	}
Population::~Population( )
	{
		destroy( );
	}
void Population::destroy( ){
	int Ctr =0;
	for(map<Individual, double>::iterator Ind_iterator = m_Individuals.begin( ); 
		Ind_iterator != m_Individuals.end( );
		Ind_iterator++){
			Ctr++;
			delete Ind_iterator->first;
		}
	
	m_Individuals.eraseAll( );
	for( size_t i=0; i < Taxonomie.size( ); i++ )
		delete Taxonomie[i];
	Taxonomie.erase(Taxonomie.begin( ), Taxonomie.end( ));	
	}

size_t Population::indexOf(Individual Ind){
	size_t Ctr = 0;
	map<Individual, double>::iterator Ind_iterator = m_Individuals.begin( ); 
	while(Ind_iterator != m_Individuals.end( ) && Ind_iterator->first != Ind){
		Ctr++;
		Ind_iterator ++;
		}
	if(Ind_iterator != m_Individuals.end( )) return Ctr;
	throw string("At size_t Population<INDIVIDUAL>::nextIndividualIndex(size_t index)");
	}


pair<INDIVIDUAL*, double> Population::operator[ ] (const size_t& index){
//	ASSERT(0<=index && index<size( ));
	size_t Ctr = 0;
	map<Individual, double>::iterator Ind_iterator = m_Individuals.begin( ); 
	while(Ctr < index){
		Ind_iterator++;
		Ctr++;
		}
	return *Ind_iterator;
	}


size_t Population::size()const{
	return this->m_Individuals.size( );
	}


size_t Population::removeDeadBeats( ){
	size_t Ctr = 0;
	vector<Individual> DB;
	map<Individual, double>::iterator Ind_iterator;
	for(Ind_iterator = m_Individuals.begin( ); Ind_iterator != m_Individuals.end( ); Ind_iterator++){
		if(Ind_iterator->second < 0.00001){
			DB.push_back(Ind_iterator->first);
			delete Ind_iterator->first;
			Ctr++;
			}
		}
	for(size_t i=0; i<DB.size( ); i++)
	m_Individuals.erase(DB[i]);
	return Ctr;
	}


Individual Population::getSomeLuckyGuy( ) const{
	map<double, pair<Individual, double> >* NormFitVals = this->normalizedFitnessStats( );
	double wheel = (double)((rand( )%1000)+1)/(double)1000.0;
	map<double, pair<Individual, double> >::iterator NormStat = NormFitVals->begin( );
	while(NormStat->first < wheel){
			NormStat++;
		}
	Individual Res = NormStat->second.first;
	delete NormFitVals;
	return Res;
	}

Individual Population::getMate( Individual Dad ) const{
	for(size_t i=0; i<Taxonomie.size( ); i++){
		Species* Spc =Taxonomie[i];
		if(Spc->belongToSpecie(Dad)){
			if(Spc->size( ) > 1){
				Individual SM = NULL;
				while (!SM || SM == Dad){
					size_t index = rand( )%Spc->size( ); 
					SM = Taxonomie[i]->operator[](index);
					}
					return SM;
				}
			else{
				return NULL;
				}
			}
		}
	return NULL;
}
Individual Population::getBest( void ){
	map<Individual, double>::iterator Ind_iterator;
	map<Individual, double>::iterator Best_iterator = m_Individuals.begin( );
	for(Ind_iterator = m_Individuals.begin( ); Ind_iterator !=  m_Individuals.end( ); Ind_iterator++)
		if(Ind_iterator->second > Best_iterator->second)
			Best_iterator = Ind_iterator;
	return Best_iterator->first;
	}

void Population::select(Ticker TicToc){
    typedef	map<Individual, double> POPULATION_SUBSET;
	removeDeadBeats( );		
	if(Params->SelectionSize >= size( )){
		this->fillByBreeding( TicToc );
		}
	else{
		bool GoOn = true;
		POPULATION_SUBSET NewPop;
		while ((NewPop.size( ) < Params->EliteSize) && GoOn){
			POPULATION_SUBSET::iterator Best_iterator = m_Individuals.begin( );
			POPULATION_SUBSET::iterator Ind_iterator;
			for(Ind_iterator = m_Individuals.begin( ); Ind_iterator !=  m_Individuals.end( ); Ind_iterator++)
				if(Ind_iterator->second > Best_iterator->second)
					Best_iterator = Ind_iterator;
			NewPop.insert(*Best_iterator);
			m_Individuals.erase(Best_iterator);
			if(TicToc) GoOn = (*TicToc)( );
			}	
		while ((NewPop.size( ) < Params->SelectionSize) && GoOn){
			POPULATION_SUBSET::iterator Survivor = m_Individuals.find(getSomeLuckyGuy( ));
			NewPop.insert(*Survivor);
			m_Individuals.erase(Survivor);
			if(TicToc) GoOn = (*TicToc)( );
			}
		destroy( );
		this->insertMap(NewPop);
		}
	}


void Population::evaluateAll(double FitFunc (Individual, void*, time_t), void* DocPtr, Ticker TicToc){
	map<Individual, double>::iterator Ind_iterator;
	time_t timeLeft = this->Params->MaxEvaluationTime;
	time_t avgTimePerInd;
	size_t leftToEval = this->size( ); 
	bool GoOn = true;
	for(Ind_iterator = m_Individuals.begin( ); Ind_iterator != m_Individuals.end( ); Ind_iterator++){
		time_t evalTime = time(NULL);
		if((Ind_iterator->second  <= 0.0f) && timeLeft > 0){
				avgTimePerInd = (time_t)((double)timeLeft / (double)leftToEval);
				Ind_iterator->second = FitFunc(Ind_iterator->first, DocPtr, avgTimePerInd );
			}
		leftToEval--;
		evalTime = time(NULL) - evalTime;
		timeLeft = timeLeft - evalTime;
		if(TicToc) GoOn = (*TicToc)( );
		}
	}


#define BREEDING_TICKER 0
#define EVAL_TICKER 1
#define SELECT_TICKER 2
#define GO_TO_NEXT_GENERATION_TICKER 3
void Population::goToNextGeneration(double FitFunc (Individual, void*, time_t), void* DocPtr, vector<Ticker> Tickers){	
	if(Tickers.size( ) != 4) throw "pebble";
	bool GoOn = true;
	if(Tickers[GO_TO_NEXT_GENERATION_TICKER]) GoOn = (*(Tickers[GO_TO_NEXT_GENERATION_TICKER]))( );
	if(GoOn) fillByBreeding(Tickers[BREEDING_TICKER]);
	if(Tickers[GO_TO_NEXT_GENERATION_TICKER]) GoOn = (*(Tickers[GO_TO_NEXT_GENERATION_TICKER]))( );
	if(GoOn) evaluateAll(FitFunc, DocPtr, Tickers[EVAL_TICKER]);
	if(Tickers[GO_TO_NEXT_GENERATION_TICKER]) GoOn = (*(Tickers[GO_TO_NEXT_GENERATION_TICKER]))( );
	if(GoOn) select(Tickers[SELECT_TICKER]);
	if(Tickers[GO_TO_NEXT_GENERATION_TICKER]) GoOn = (*(Tickers[GO_TO_NEXT_GENERATION_TICKER]))( );
	if(GoOn) fillByBreeding(Tickers[BREEDING_TICKER]);
	generationCount++;
	}


void Population::resetFitness( ){
	map<Individual, double>::iterator Ind_iterator;
	for(Ind_iterator = m_Individuals.begin( ); Ind_iterator != m_Individuals.end( ); Ind_iterator++)
		Ind_iterator->second = 0.0f; 
	}


map<double, pair<INDIVIDUAL*, double> >*  Population::normalizedFitnessStats( ) const{
	//The second element of the pair is the normalized fitness of the first element of the pair
	//The key is the running sum of the normalized fitness of the individual
	typedef  map<double, pair<INDIVIDUAL*, double> > FitnessStatistics;
	FitnessStatistics* FitnessStats = new FitnessStatistics( );
	double sum = this->sumFitness( );
	if(sum){
		map<Individual, double>::const_iterator Ind_iterator = m_Individuals.begin( );
		map<Individual, double>::const_iterator PrevIterator = m_Individuals.begin( );
		while(Ind_iterator != m_Individuals.end( )){				
					PrevIterator = Ind_iterator;
					double NormedFit = Ind_iterator->second / sum;
					double RunFit;
					if(Ind_iterator == m_Individuals.begin( )){
						RunFit = NormedFit;
						Ind_iterator++;
						}
					else{
						Ind_iterator++;
						if( Ind_iterator == m_Individuals.end( ))
							RunFit = 1.0;
						else
							RunFit = (FitnessStats->rbegin( )->first) + NormedFit;
						}
					
					FitnessStats->operator[ ](RunFit) = pair<Individual, double>(PrevIterator->first, NormedFit);  
			}
	}
	return FitnessStats;
	}




double Population::sumFitness( ) const{
	double Sum = 0.0f;
	map<Individual, double>::const_iterator Ind_iterator;
	for(Ind_iterator = m_Individuals.begin( ); Ind_iterator != m_Individuals.end( ); Ind_iterator++)
		Sum+=Ind_iterator->second;
	return Sum;
	}


double Population::avgFitness( ) const{
		return sumFitness( )/((double)size( ));
	}	

void Population::mutate(Individual Ind){
	while(rand( )%1000 < this->Params->MutationProbability){
		(*Mutate)(Ind);
		}
}


void Population::fillByBreeding(Ticker TicToc ){

	double SF = sumFitness( );   	
	
	mapIndDoub newGeneration;
	size_t totalNumOffspringsNeeded = this->Params->MaxPopulationSize - size( );
	size_t numOffspringsStillNeeded = totalNumOffspringsNeeded;
	
	while(numOffspringsStillNeeded > 0){	
		Individual  Dad		= getSomeLuckyGuy( );
		Individual  Mom		= getMate(Dad); 
		Individual Litter;
		if(Mom){
			Litter =	(*Spawn)(Dad, Mom);
			if(Litter){
				mutate(Litter);
				newGeneration[Litter] = 0.0f;
				numOffspringsStillNeeded --;
				}
			}
		else{
			Litter = (Individual) Dad->clone( );
			mutate(Litter);
			newGeneration[Litter] = 0.0f;
			numOffspringsStillNeeded --;
			}
		if(TicToc) if(!(*TicToc)( ))  numOffspringsStillNeeded = 0;
		}
	mapIndDoub::iterator   genIt = newGeneration.begin( );
	for(size_t i = 0; i < totalNumOffspringsNeeded; i++){
		this->insert(genIt->first);
		genIt++;
		}
	while( genIt != newGeneration.end( )){
		delete genIt->first;
		genIt++;
		}
	}

void Population::fillByGenerating( Ticker TicToc ){
	bool GoOn = true;
	while((m_Individuals.size( ) < Params->MaxPopulationSize) && (GoOn)){
			insert((*Generator)( ));
			if(TicToc) GoOn = (*TicToc)( );
		}
	}
















